import numpy as np

def Ufun(x, a, k, m):
    return k * ((x - a) ** m) * (x > a) + k * ((-x - a) ** m) * (x < -a)

def F1(x): return np.sum(x**2)
def F2(x): return np.sum(np.abs(x)) + np.prod(np.abs(x))
def F3(x): return np.sum([np.sum(x[:i+1])**2 for i in range(len(x))])
def F4(x): return np.max(np.abs(x))
def F5(x): return np.sum(100 * (x[1:] - x[:-1]**2)**2 + (x[:-1] - 1)**2)
def F6(x): return np.sum((x + 0.5)**2)
def F7(x): return np.sum((np.arange(1, len(x)+1)) * x**4) + np.random.rand()
def F8(x): return np.sum(-x * np.sin(np.sqrt(np.abs(x))))
def F9(x): return np.sum(x**2 - 10 * np.cos(2 * np.pi * x)) + 10 * len(x)
def F10(x): return -20 * np.exp(-0.2 * np.sqrt(np.sum(x**2) / len(x))) - np.exp(np.sum(np.cos(2 * np.pi * x)) / len(x)) + 20 + np.exp(1)
def F11(x): return np.sum(x**2) / 4000 - np.prod(np.cos(x / np.sqrt(np.arange(1, len(x)+1)))) + 1
def F12(x):
    x = np.array(x)
    dim = len(x)
    term1 = (np.pi / dim) * (10 * (np.sin(np.pi * (1 + (x[0] + 1) / 4)))**2)
    term2 = np.sum(((x[:-1] + 1) / 4)**2 * (1 + 10 * (np.sin(np.pi * (1 + (x[1:] + 1) / 4)))**2))
    term3 = ((x[-1] + 1) / 4)**2
    return term1 + term2 + term3 + np.sum(Ufun(x, 10, 100, 4))
def F13(x):
    x = np.array(x)
    dim = len(x)
    return 0.1 * ((np.sin(3 * np.pi * x[0]))**2 + np.sum((x[:-1] - 1)**2 * (1 + (np.sin(3 * np.pi * x[1:]))**2)) + ((x[-1] - 1)**2) * (1 + (np.sin(2 * np.pi * x[-1]))**2)) + np.sum(Ufun(x, 5, 100, 4))
def F14(x):
    x = np.array(x)
    aS = np.array([
        [-32, -16, 0, 16, 32] * 5,
        [-32] * 5 + [-16] * 5 + [0] * 5 + [16] * 5 + [32] * 5
    ])
    bS = np.array([np.sum((x - aS[:, j])**6) for j in range(25)])
    return (1 / (0.002 + np.sum(1.0 / (np.arange(1, 26) + bS))))

def F15(x):
    x = np.array(x)
    aK = np.array([.1957, .1947, .1735, .16, .0844, .0627, .0456, .0342, .0323, .0235, .0246])
    bK = 1 / np.array([.25, .5, 1, 2, 4, 6, 8, 10, 12, 14, 16])
    return np.sum((aK - ((x[0] * (bK**2 + x[1]*bK)) / (bK**2 + x[2]*bK + x[3])))**2)

def F16(x):
    x1, x2 = x
    return 4*x1**2 - 2.1*x1**4 + (x1**6)/3 + x1*x2 - 4*x2**2 + 4*x2**4

def F17(x):
    x1, x2 = x
    return (x2 - (5.1 * x1**2) / (4 * np.pi**2) + 5 * x1 / np.pi - 6)**2 + 10 * (1 - 1/(8*np.pi)) * np.cos(x1) + 10

def F18(x):
    x1, x2 = x
    return (1 + (x1 + x2 + 1)**2 * (19 - 14*x1 + 3*x1**2 - 14*x2 + 6*x1*x2 + 3*x2**2)) * \
           (30 + (2*x1 - 3*x2)**2 * (18 - 32*x1 + 12*x1**2 + 48*x2 - 36*x1*x2 + 27*x2**2))

def F19(x):
    aH = np.array([[3,10,30],[.1,10,35],[3,10,30],[.1,10,35]])
    cH = np.array([1,1.2,3,3.2])
    pH = np.array([[.3689,.117,.2673],[.4699,.4387,.747],[.1091,.8732,.5547],[.03815,.5743,.8828]])
    return -np.sum([cH[i]*np.exp(-np.sum(aH[i]*(x - pH[i])**2)) for i in range(4)])

def F20(x):
    aH = np.array([[10,3,17,3.5,1.7,8],[.05,10,17,.1,8,14],[3,3.5,1.7,10,17,8],[17,8,.05,10,.1,14]])
    cH = np.array([1,1.2,3,3.2])
    pH = np.array([[.1312,.1696,.5569,.0124,.8283,.5886],
                   [.2329,.4135,.8307,.3736,.1004,.9991],
                   [.2348,.1415,.3522,.2883,.3047,.6650],
                   [.4047,.8828,.8732,.5743,.1091,.0381]])
    return -np.sum([cH[i]*np.exp(-np.sum(aH[i]*(x - pH[i])**2)) for i in range(4)])

def F21(x):
    aSH = np.array([
        [4,4,4,4],[1,1,1,1],[8,8,8,8],[6,6,6,6],[3,7,3,7],
        [2,9,2,9],[5,5,3,3],[8,1,8,1],[6,2,6,2],[7,3.6,7,3.6]
    ])
    cSH = np.array([.1,.2,.2,.4,.4,.6,.3,.7,.5,.5])
    return -np.sum([1 / (np.sum((x - aSH[i])**2) + cSH[i]) for i in range(5)])

def F22(x):
    aSH = np.array([
        [4,4,4,4],[1,1,1,1],[8,8,8,8],[6,6,6,6],[3,7,3,7],
        [2,9,2,9],[5,5,3,3],[8,1,8,1],[6,2,6,2],[7,3.6,7,3.6]
    ])
    cSH = np.array([.1,.2,.2,.4,.4,.6,.3,.7,.5,.5])
    return -np.sum([1 / (np.sum((x - aSH[i])**2) + cSH[i]) for i in range(7)])

def F23(x):
    aSH = np.array([
        [4,4,4,4],[1,1,1,1],[8,8,8,8],[6,6,6,6],[3,7,3,7],
        [2,9,2,9],[5,5,3,3],[8,1,8,1],[6,2,6,2],[7,3.6,7,3.6]
    ])
    cSH = np.array([.1,.2,.2,.4,.4,.6,.3,.7,.5,.5])
    return -np.sum([1 / (np.sum((x - aSH[i])**2) + cSH[i]) for i in range(10)])
def get_functions_details(F):
    details = {
        "F1": ( -100, 100, 30,F1),
        "F2": ( -10, 10, 30,F2),
        "F3": (-100, 100, 30,F3),
        "F4": ( -100, 100, 30,F4),
        "F5": ( -30, 30, 30,F5),
        "F6": ( -100, 100, 30,F6),
        "F7": ( -1.28, 1.28, 30,F7),
        "F8": ( -500, 500, 30,F8),
        "F9": ( -5.12, 5.12, 30,F9),
        "F10": ( -32, 32, 30,F10),
        "F11": ( -600, 600, 30,F11),
        "F12": ( -50, 50, 30,F12),
        "F13": ( -50, 50, 30,F13),
        "F14": ( -65.536, 65.536, 2,F14),
        "F15": ( -5, 5, 4,F15),
        "F16": ( -5, 5, 2,F16),
        "F17": ( [-5, 0], [10, 15], 2,F17),
        "F18": ( -2, 2, 2,F18),
        "F19": ( 0, 1, 3,F19),
        "F20": ( 0, 1, 6,F20),
        "F21": ( 0, 10, 4,F21),
        "F22": ( 0, 10, 4,F22),
        "F23": ( 0, 10, 4,F23)
    }
    return details[F]
